import { decodeAll } from "./codec/codec";
import { CodecBase } from "./codec/codec_type";
import { ExecErr } from "./error";
import { Type } from "./proto";
import { handle_notify, handle_notify_ack } from "./recv_notify";
import { toHex } from "./utils";

export class RecvFrame {

    buf: number[];

    type() {
        return this.buf[0];
    }

    seq() {
        return this.buf[1];
    }

    cmd() {
        return this.buf[2];
    }

    parse_res(...args: CodecBase[]) {
        const ec = this.buf[3];
        if (ec != 0) {
            throw new ExecErr(ec);
        }
        decodeAll(this.buf, 4, ...args);
    }

    parse_notify(...args: CodecBase[]) {
        decodeAll(this.buf, 3, ...args);
    }

    constructor(buf: number[]) {
        this.buf = buf;
    }

    toString() {
        return toHex(this.buf);
    }
};

const resultMap = new Map<number, (_: RecvFrame) => void>();

function onResult(frame: RecvFrame) {
    //console.log('result:', frame.toString());
    let key = (frame.type() << 8) + frame.seq();
    let fun = resultMap.get(key);
    if (fun == null) {
        console.error('not found handler');
        return;
    }
    resultMap.delete(key);
    fun(frame);
}

export function registerResult(key: number, fn: (_: RecvFrame)=>void) {
    resultMap.set(key, fn);
}

export function recv(buf: number[]) {
    const frame = new RecvFrame(buf);
    switch (frame.type()) {
        case Type.ACK:
        case Type.PONG:
        case Type.SIMPLE_RES:
        case Type.RES:
            onResult(frame);
        break;

        case Type.NOTIFY:
            handle_notify(frame);
        break;

        case Type.NOTIFY_ACK:
            handle_notify_ack(frame);
        break;
    }
}

